#pragma once

#include <afx.h>
#include <iostream>
#include <string>
#include <list>

#include "Function.h"
#include "Variable.h"

using namespace std;

enum StatementType {
	tStatementIf,
	tStatementFunction,		// f(x)
	tStatementOperation,		// a = b + 1
	tStatementWhile,
	tStatementFunctionAssign		// a = f(x)
};

enum CompType {
	Equal,
	LessThan,
	LessThanEqual,
	GreaterThan,
	GreaterThanEqual
};

enum OperationType {
	tAdd,
	tSubtract,
	tMult,
	tDiv,
	tMod
};

class CStatement
{
public:
	CStatement();
	~CStatement();

	// Execute will be called repeatedly until it returns true
	virtual bool Execute();

protected:
	StatementType m_Type;
};

/////////////////////////////////////
class CStatementWhile : public CStatement
{
public:
	CStatementWhile(CVariable *left, CVariable *right, bool not, CompType comp);
	CStatementWhile();
	~CStatementWhile();

	void AddStatement(CStatement *var);
	bool Execute();
private:
	CVariable *m_Left, *m_Right;
	bool m_Not;
	CompType m_CompType;
	list<CStatement*> m_Statements;
	int m_ExecPos;
};


/////////////////////////////////////
class CStatementFunction : public CStatement
{
public:
	CStatementFunction(CFunction var);
	CStatementFunction();
	~CStatementFunction();

	bool Execute();

	CVariable* GetFunctionReturn();

private:
	CFunction m_Function;
};

/////////////////////////////////////
class CStatementFunctionAssign : public CStatement
{
public:
	CStatementFunctionAssign(CStatementFunction fn, CVariable *svar);
	CStatementFunctionAssign();
	~CStatementFunctionAssign();

	bool Execute();

private:
	CStatementFunction m_FunctionStatement;
	CVariable *m_Var;
};

/////////////////////////////////////
class CStatementOperation : public CStatement
{
public:
	CStatementOperation(CVariable *assign, CVariable *right, CVariable *left,
							OperationType type);
	CStatementOperation();
	~CStatementOperation();

	bool Execute();

private:
	OperationType m_CompType;
	CVariable *m_Assign, *m_Left, *m_Right;
};

/////////////////////////////////////
class CStatementIf : public CStatement
{
public:
	// constuctor takes the line with 'if' as an argument
	// further if statements will be added in another function
	CStatementIf(CVariable *left, CVariable *right, bool not, CompType comp);
	CStatementIf();
	~CStatementIf();

	// bool AddStatement(list<CString> line);
	void AddStatement(CStatement *var);
	void FlagElse();
	bool Execute();
private:
	bool m_Not, m_Else;
	CVariable *m_Left, *m_Right;
	list<CStatement*> m_IfStatements;
	list<CStatement*> m_ElseStatements;
	CompType m_CompType;
	int m_ExecPos;
};